#this file has functions to keep track of captures and definite groups

import misc
import board
import copy

def adjacencies(x,y, board):
	#x:int y:int board:matrix
	#2 means edge
	#nesw: north south east west
	try:
		n = board.returnpoint(x,y-1)
	except IndexError:
		n = 2

	try:
		e = board.returnpoint(x+1,y)
	except IndexError:
		e = 2

	try:
		s = board.returnpoint(x,y+1)
	except IndexError:
		s = 2

	try:
		w = board.returnpoint(x-1,y)
	except IndexError:
		w = 2

	return [n,e,s,w]

 

def findspanningtree(color, x,y,board):
#given a coordinate that definitely holds a stone of a certain color, this function
#finds all connected stones

       frontier = [[x,y]]
       explored = []
       outputlist = [[x,y]]

       while frontier:

               carfrontier = frontier.pop(0)
	       explored.append(eval(repr(carfrontier)))
               adj = adjacencies(carfrontier[0], carfrontier[1], board)


	       #if the adjacent is the right color and not an explored coordinate yet

               if adj[0] == color and (not misc.isincluded([(carfrontier[0]),(carfrontier[1]-1)], explored)) and carfrontier[1] != 0:
                       frontier.append([(carfrontier[0]),(carfrontier[1]-1)])
                       outputlist.append([(carfrontier[0]),(carfrontier[1]-1)])

               if adj[1] == color and (not misc.isincluded([(carfrontier[0]+1),(carfrontier[1])], explored)):
                       frontier.append([(carfrontier[0]+1),(carfrontier[1])])
                       outputlist.append([(carfrontier[0]+1),(carfrontier[1])])

               if adj[2] == color and (not misc.isincluded([(carfrontier[0]),(carfrontier[1]+1)], explored)):
                       frontier.append([(carfrontier[0]),(carfrontier[1]+1)])
                       outputlist.append([(carfrontier[0]),(carfrontier[1]+1)])

               if adj[3] == color and (not misc.isincluded([(carfrontier[0]-1),(carfrontier[1])], explored)) and carfrontier[0] != 0:
                       frontier.append([(carfrontier[0]-1),(carfrontier[1])])
                       outputlist.append([(carfrontier[0]-1),(carfrontier[1])])


       return outputlist	
	

def groups(color, goboard):
	#goboard:board object
	#color is either 1(black) or -1(white)
	#color is specified in the first item of the group coordinate list

	#get a list of all coordinates [x,y] on the board
	outputlist = []
	globalcoordlist = []
	for i in range(goboard.size):
		for j in range(goboard.size):
			globalcoordlist.append([j,i])


	while globalcoordlist: #while this list is not empty yet
		testcoord = eval(repr(globalcoordlist[0]))
		
		if goboard.returnpoint(testcoord[0],testcoord[1]) == color:
			localgroup = findspanningtree(color, testcoord[0], testcoord[1], goboard)
						

			#remove from the global list
			for i in range(len(localgroup)):
				globalcoordlist.remove(localgroup[i])

			#add the group to the output list
			outputlist.append(eval(repr(localgroup)))

		else:
			globalcoordlist.remove(testcoord)

	return outputlist


			
def liberties(group, board):
	outputlist = []
	for i in range(len(group)):
		adj = adjacencies(group[i][0],group[i][1],board)
		
		if adj[0] == 0 and group[i][1] != 0:
			outputlist.append([group[i][0],group[i][1]-1])	
		if adj[1] == 0:
			outputlist.append([group[i][0]+1,group[i][1]])
		if adj[2] == 0:
			outputlist.append([group[i][0],group[i][1]+1])
		if adj[3] == 0 and group[i][0] != 0:
			outputlist.append([group[i][0]-1,group[i][1]])

	return misc.unique(outputlist)

def libertieslist(grouplist, board):
	#returns a list of liberties for each group in a list of groups
	outputlist = []
	for i in range(len(grouplist)):
		outputlist.append(liberties(grouplist[i],board))
	return outputlist



#the point of these following two functions is to play out all the rules of the board given a certain coordinate and color that was just played

def islegal(color, move, board):
	#finds if given move for the given color is legal (disregarding ko for now)
	#color: color that just moved
	#move: coordinates of the move [x,y]


	#check if the coordinate is even on the board
	if move[0]<0 or move[0]>(board.size-1) or move[1]<0 or move[1]>(board.size-1):
		return False

	#check if the coordinate is already occupied
	if misc.isincluded(move, board.stonelist):
		return False


	#check for suicide

	board.setpoint(move[0],move[1],color) #temporarily place the stone
	
	grouplist = groups(color, board)
	othergrouplist = groups(color*-1, board)
	groupliberties = libertieslist(grouplist, board)
	othergroupliberties = libertieslist(othergrouplist, board)
	
	if misc.isincluded([],othergroupliberties): #if something got captured, its legal. 
		#This could also happen on the first move for white (he has no stones) so his liberty list is a null set, that means the next move is legal anyway
		board.setpoint(move[0],move[1],0) #test is done, take stone off
		return True

	if misc.isincluded([],groupliberties): #if its suicide
		board.setpoint(move[0],move[1],0) #test is done, take stone off
		return False

	board.setpoint(move[0],move[1],0) #remove the stone after checking, will be officially placed in manage board
	
	return True #just a normal move with no captures or suicides
	
	
#call this after checking if the move is legal
def newboardstate(color, move, board):
	#takes the color that just played (1 or -1), the move ([x,y]) and the board
	newboard = copy.deepcopy(board)
	newboard.setpoint(move[0],move[1],color)
	othergrouplist = groups(color*-1, newboard)
	othergroupliberties = libertieslist(othergrouplist, newboard)
	
	if misc.isincluded([], othergroupliberties): #if it captured something, remove the stones
		indexes = misc.finditems([],othergroupliberties)
		for i in range(len(indexes)):
			newboard.removestones(othergrouplist[indexes[i]])

	return newboard
	
